#! /bin/sh

# Set a version string for this script.
scriptversion=2011-11-20.12; # UTC

# A pluggable option parser for Bourne shell.
# Written by Gary V. Vaughan, 2010

# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions.  There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Please report bugs or propose patches to bug-gnulib@gnu.org.


## ------ ##
## Usage. ##
## ------ ##

# This file is a library for parsing options in your shell scripts along
# with assorted other useful supporting features that you can make use
# of too.
#
# For the simplest scripts you might need only:
#
#   #!/bin/sh
#   . relative/path/to/options-parser
#   scriptversion=1.0
#   func_options ${1+"$@"}
#   eval set dummy "$func_options_result"; shift
#   ...rest of your script...
#
# In order for the `--version' option to work, you will need to have a
# suitably formatted comment like the one at the top of this file
# starting with '# Written by ' and ending with '# warranty; '.
#
# For `-h' and `--help' to work, you will also need a one line
# description of your script's purpose in a comment directly above the
# '# Written by ' line, like the one at the top of this file.
#
# The default options also support `--debug', which will turn on shell
# execution tracing (see the comment above debug_cmd below for another
# use), and `--verbose' and the func_verbose function to allow your script
# to display verbose messages only when your user has specified
# `--verbose'.
#
# After sourcing this file, you can plug processing for additional
# options by amending the variables from the `Configuration' section
# below, and following the instructions in the `Option parsing'
# section further down.

## -------------------- ##
## Shell normalisation. ##
## -------------------- ##

# Some shells need a little help to be as Bourne compatible as possible.
# Before doing anything else, make sure all that help has been provided!

DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
fi

# NLS nuisances.
LANGUAGE=C
export LANGUAGE

# Ensure file names are sorted consistently across platforms.
LC_ALL=C
export LC_ALL

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH


## ------------------------------- ##
## User overridable command paths. ##
## ------------------------------- ##

# All uppercase variable names are used for environment variables.  These
# variables can be overridden by the user before calling a script that
# uses them if a suitable command of that name is not already available
# in the command search PATH.

: ${SED="sed"}


## -------------- ##
## Configuration. ##
## -------------- ##

# You should override these variables in your script after sourcing this
# file so that they reflect the customisations you have added to the
# option parser.

# The usage line for option parsing errors and the start of `-h' and
# `--help' output messages. You can embed shell variables for delayed
# expansion at the time the message is displayed, but you will need to
# quote other shell meta-characters carefully to prevent them being
# expanded when the contents are evaled.
usage='$progpath [OPTION]...'

# Short help message in response to `-h' and `--help'.  Add to this or
# override it after sourcing this library to reflect the full set of
# options your script accepts.
usage_message="\
      --debug        enable verbose shell tracing
  -v, --verbose      verbosely report processing
      --version      print version information and exit
  -h, --help         print short or long help message and exit
"

# Additional text appended to `usage_message' in response to `--help'.
long_help_message=

# Help message printed before fatal option parsing errors.
fatal_help='Try \`$progname --help'\'' for more information.'



## ----------------- ##
## Global variables. ##
## ----------------- ##

# Except for the global variables explicitly listed below, the following
# functions in the '^func_' namespace, and the '^require_' namespace
# variables initialised in the `Resource management' section, sourcing
# this file will not pollute your global namespace with anything
# else. There's no portable way to scope variables in Bourne shell
# though, so actually running these functions will sometimes place
# results into a variable named after the function, and often use
# temporary variables in the `^_G_' namespace. If you are careful to
# avoid using those namespaces casually in your sourcing script, things
# should continue to work as you expect. And, of course, you can freely
# overwrite any of the functions or variables defined here before
# calling anything to customize them.

EXIT_SUCCESS=0
EXIT_FAILURE=1
EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
EXIT_SKIP=77      # $? = 77 is used to indicate a skipped test to automake.

# Allow overriding, eg assuming that you follow the convention of
# putting `$debug_cmd' at the start of all your functions, you can get
# bash to show function call trace with:
#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash bootstrap
debug_cmd=${debug_cmd-":"}
exit_cmd=:

dirname='s|/[^/]*$||'
basename='s|^.*/||'

nl='
'

# There are still modern systems that have problems with `echo' mis-
# handling backslashes, among others, so make sure $bs_echo is set to a
# command that correctly interprets backslashes.
# (this code from Autoconf 2.68)

# Printing a long string crashes Solaris 7 /usr/bin/printf.
bs_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
bs_echo=$bs_echo$bs_echo$bs_echo$bs_echo$bs_echo
bs_echo=$bs_echo$bs_echo$bs_echo$bs_echo$bs_echo$bs_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $bs_echo`" = "X$bs_echo") 2>/dev/null; then
  bs_echo='print -r --'
  bs_echo_n='print -rn --'
elif (test "X`printf %s $bs_echo`" = "X$bs_echo") 2>/dev/null; then
  bs_echo='printf %s\n'
  bs_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $bs_echo) 2>/dev/null`" = "X-n $bs_echo"; then
    bs_echo_body='eval /usr/ucb/echo -n "$1$nl"'
    bs_echo_n='/usr/ucb/echo -n'
  else
    bs_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    bs_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$nl"*)
	expr "X$arg" : "X\\(.*\\)$nl";
	arg=`expr "X$arg" : ".*$nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$nl"
    '
    export bs_echo_n_body
    bs_echo_n='sh -c $bs_echo_n_body bs_echo'
  fi
  export bs_echo_body
  bs_echo='sh -c $bs_echo_body bs_echo'
fi

# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
# is ksh but when the shell is invoked as "sh" and the current value of
# the _XPG environment variable is not equal to 1 (one), the special
# positional parameter $0, within a function call, is the name of the
# function.
progpath=$0

# The name of this program.
progname=`$bs_echo "$progpath" |$SED "$basename"`


## ------------------------- ##
## Hook function management. ##
## ------------------------- ##

# This section contains functions for adding, removing, and running hooks
# to the main code.  A hook is just a named list of of function, that can
# be run in order later on.


# func_append VAR VALUE
# ---------------------
# Append VALUE onto the existing contents of VAR.
if (eval 'x=a; x+=" b"; test "x$x" = "xa b"') 2>/dev/null
then
  # This is an XSI compatible shell, allowing a faster implementation...
  eval 'func_append ()
  {
    $debug_cmd

    eval "$1+=\$2"
  }'
else
  # ...otherwise fall back to using expr, which is often a shell builtin.
  func_append ()
  {
    $debug_cmd

    eval "$1=\$$1\$2"
  }
fi


# func_hookable FUNC_NAME
# -----------------------
# Declare that FUNC_NAME will run hooks added with
# `func_add_hook FUNC_NAME ...'.
func_hookable ()
{
    $debug_cmd

    func_append hookable_fns " $1"
}


# func_add_hook FUNC_NAME HOOK_FUNC
# ---------------------------------
# Request that FUNC_NAME call HOOK_FUNC before it returns.  FUNC_NAME must
# first have been declared "hookable" by a call to `func_hookable'.
func_add_hook ()
{
    $debug_cmd

    case " $hookable_fns " in
      *" $1 "*) ;;
      *) func_fatal_error "\`$1' does not accept hook functions." ;;
    esac

    eval func_append ${1}_hooks '" $2"'
}


# func_remove_hook FUNC_NAME HOOK_FUNC
# ------------------------------------
# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
func_remove_hook ()
{
    $debug_cmd

    eval ${1}_hooks='`$bs_echo "\$'$1'_hooks" |$SED "s| '$2'||"`'
}


# func_run_hooks FUNC_NAME [ARG]...
# ---------------------------------
# Run all hook functions registered to FUNC_NAME.
# It is assumed that the list of hook functions contains nothing more
# than a whitespace-delimited list of legal shell function names, and
# no effort is wasted trying to catch shell meta-characters or preserve
# whitespace.
func_run_hooks ()
{
    $debug_cmd

    case " $hookable_fns " in
      *" $1 "*) ;;
      *) func_fatal_error "\`$1' does not support hook funcions.n" ;;
    esac

    eval _G_hook_fns=\$$1_hooks; shift

    for _G_hook in $_G_hook_fns; do
      eval $_G_hook '"$@"'

      # store returned options list back into positional
      # parameters for next `cmd' execution.
      eval set dummy \$${_G_hook}_result; shift
    done

    func_quote_for_eval ${1+"$@"}
    func_run_hooks_result=$func_quote_for_eval_result
}



## --------------- ##
## Option parsing. ##
## --------------- ##

# In order to add your own option parsing hooks, you must accept the
# full positional parameter list in your hook function, remove any
# options that you action, and then pass back the remaining unprocessed
# options in `<hooked_function_name>_result', escaped suitably for
# `eval'.  Like this:
#
#    my_options_prep ()
#    {
#        $debug_cmd
#
#        # Extend the existing usage message.
#        usage_message=$usage_message'
#      -s, --silent       don'\''t print informational messages
#    '
#
#        func_quote_for_eval ${1+"$@"}
#        my_options_prep_result=$func_quote_for_eval_result
#    }
#    func_add_hook func_options_prep my_options_prep
#
#
#    my_silent_option ()
#    {
#        $debug_cmd
#
#        # Note that for efficiency, we parse as many options as we can
#        # recognise in a loop before passing the remainder back to the
#        # caller on the first unrecognised argument we encounter.
#        while test $# -gt 0; do
#          opt=$1; shift
#          case $opt in
#            --silent|-s) opt_silent=: ;;
#            # Separate non-argument short options:
#            -s*)         func_split_short_opt "$_G_opt"
#                         set dummy "$func_split_short_opt_name" \
#                             "-$func_split_short_opt_arg" ${1+"$@"}
#                         shift
#                         ;;
#            *)            set dummy "$_G_opt" "$*"; shift; break ;;
#          esac
#        done
#
#        func_quote_for_eval ${1+"$@"}
#        my_silent_option_result=$func_quote_for_eval_result
#    }
#    func_add_hook func_parse_options my_silent_option
#
#
#    my_option_validation ()
#    {
#        $debug_cmd
#
#        $opt_silent && $opt_verbose && func_fatal_help "\
#    \`--silent' and \`--verbose' options are mutually exclusive."
#
#        func_quote_for_eval ${1+"$@"}
#        my_option_validation_result=$func_quote_for_eval_result
#    }
#    func_add_hook func_validate_options my_option_validation
#
# You'll alse need to manually amend $usage_message to reflect the extra
# options you parse.  It's preferable to append if you can, so that
# multiple option parsing hooks can be added safely.


# func_options [ARG]...
# ---------------------
# All the functions called inside func_options are hookable. See the
# individual implementations for details.
func_hookable func_options
func_options ()
{
    $debug_cmd

    func_options_prep ${1+"$@"}
    eval func_parse_options \
        ${func_options_prep_result+"$func_options_prep_result"}
    eval func_validate_options \
        ${func_parse_options_result+"$func_parse_options_result"}

    eval func_run_hooks func_options \
        ${func_validate_options_result+"$func_validate_options_result"}

    # save modified positional parameters for caller
    func_options_result=$func_run_hooks_result
}


# func_options_prep [ARG]...
# --------------------------
# All initialisations required before starting the option parse loop.
# Note that when calling hook functions, we pass through the list of
# positional parameters.  If a hook function modifies that list, and
# needs to propogate that back to rest of this script, then the complete
# modified list must be put in `func_run_hooks_result' before
# returning.
func_hookable func_options_prep
func_options_prep ()
{
    $debug_cmd

    # Option defaults:
    opt_verbose=false

    func_run_hooks func_options_prep ${1+"$@"}

    # save modified positional parameters for caller
    func_options_prep_result=$func_run_hooks_result
}


# func_parse_options [ARG]...
# ---------------------------
# The main option parsing loop.
func_hookable func_parse_options
func_parse_options ()
{
    $debug_cmd

    func_parse_options_result=

    # this just eases exit handling
    while test $# -gt 0; do
      # Defer to hook functions for initial option parsing, so they
      # get priority in the event of reusing an option name.
      func_run_hooks func_parse_options ${1+"$@"}

      # Adjust func_parse_options positional parameters to match
      eval set dummy $func_run_hooks_result; shift

      # Break out of the loop if we already parsed every option.
      test $# -gt 0 || break

      _G_opt=$1
      shift
      case $_G_opt in
        --debug|-x)   debug_cmd='set -x'
                      func_echo "enabling shell trace mode"
                      $debug_cmd
                      ;;

        --verbose|-v) opt_verbose=: ;;
        --version)    func_version ;;
        -\?|-h)       func_usage ;;
        --help)       func_help ;;

	# Separate optargs to long options (plugins may need this):
	--*=*)        func_split_equals "$_G_opt"
	              set dummy "$func_split_equals_lhs" \
                          "$func_split_equals_rhs" ${1+"$@"}
                      shift
                      ;;

        # Separate non-argument short options:
        -\?*|-h*|-v*|-x*)
                      func_split_short_opt "$_G_opt"
                      set dummy "$func_split_short_opt_name" \
                          "-$func_split_short_opt_arg" ${1+"$@"}
                      shift
                      ;;

        --)           set dummy "$_G_opt" "*"; shift; break ;;
        -*)           func_fatal_help "unrecognised option: \`$_G_opt'" ;;
        *)            set dummy "$_G_opt" "$*"; shift; break ;;
      esac
    done

    # save modified positional parameters for caller
    func_quote_for_eval ${1+"$@"}
    func_parse_options_result=$func_quote_for_eval_result
}


# func_validate_options [ARG]...
# ------------------------------
# Perform any sanity checks on option settings and/or unconsumed
# arguments.
func_hookable func_validate_options
func_validate_options ()
{
    $debug_cmd

    func_run_hooks func_validate_options ${1+"$@"}

    # Bail if the options were screwed!
    $exit_cmd $EXIT_FAILURE

    # save modified positional parameters for caller
    func_validate_options_result=$func_run_hooks_result
}



## -------------------- ##
## Resource management. ##
## -------------------- ##

# This section contains definitions for functions that each ensure a
# particular resource (a file, or a non-empty configuration variable for
# example) is available, and if appropriate to extract default values
# from pertinent package files. Call them using their associated
# `require_*' variable to ensure that they are executed, at most, once.
#
# It's entirely deliberate that calling these functions can set
# variables that don't obey the namespace limitations obeyed by the rest
# of this file, in order that that they be as useful as possible to
# callers.


# require_term_colors
# -------------------
# Allow display of bold text on terminals that support it.
require_term_colors=func_require_term_colors
func_require_term_colors ()
{
  $debug_cmd

  test -t 1 && {
    test -n "`tput sgr0 2>/dev/null`" && {
      tc_reset=`tput sgr0`
      test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
      tc_standout=$tc_bold
      test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
      test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
      test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
      test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
      test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
    }
  }

  require_term_colors=:
}


## ------------------##
## Helper functions. ##
## ------------------##

# This section contains the helper functions used by the rest of the
# hookable option parser framework in ascii-betical order.

# func_echo ARG...
# ----------------
# Echo program name prefixed message, taking newlines into account.
func_echo ()
{
    _G_message=$*

    save_IFS=$IFS
    IFS=$nl
    for _G_line in $_G_message; do
      IFS=$save_IFS
      $bs_echo "$progname: $_G_line"
    done
    IFS=$save_IFS
}


# func_error ARG...
# -----------------
# Echo program name prefixed message to standard error.
func_error ()
{
    $require_term_colors

    _G_message=$*
    _G_prefix="$progname: $tc_standout${tc_red}error$tc_reset: "

    save_IFS=$IFS
    IFS=$nl
    for _G_line in $_G_message; do
      IFS=$save_IFS
      $bs_echo "$_G_prefix$tc_bold$_G_line$tc_reset" 1>&2
      _G_prefix="$progname:        "
    done
    IFS=$save_IFS
}


# func_fatal_error ARG...
# -----------------------
# Echo program name prefixed message to standard error, and exit.
func_fatal_error ()
{
    func_error ${1+"$@"}
    exit $EXIT_FAILURE
}


# func_fatal_help ARG...
# ----------------------
# Echo program name prefixed message to standard error, followed by
# a help hint, and exit.
func_fatal_help ()
{
    $debug_cmd

    eval \$bs_echo \""Usage: $usage"\"
    eval \$bs_echo \""$fatal_help"\"
    func_error ${1+"$@"}
    exit $EXIT_FAILURE
}


# func_help
# ---------
# Echo long help message to standard output and exit.
func_help ()
{
    $debug_cmd

    func_usage_message
    $bs_echo "$long_help_message"
    exit 0
}


# func_missing_arg ARGNAME
# ------------------------
# Echo program name prefixed message to standard error and set global
# exit_cmd.
func_missing_arg ()
{
    $debug_cmd

    func_error "Missing argument for \`$1'."
    exit_cmd=exit
}


# func_quote_for_eval ARG...
# --------------------------
# Aesthetically quote ARGs to be evaled later.
# This function returns two values: FN_QUOTE_FOR_EVAL_RESULT
# is double-quoted, suitable for a subsequent eval, whereas
# FN_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
# which are still active within double quotes backslashified.
func_quote_for_eval ()
{
    $debug_cmd

    _G_sed_quote_subst='s|\([`"$\\]\)|\\\1|g'

    func_quote_for_eval_result=
    while test $# -gt 0; do
      case $1 in
        *[\\\`\"\$]*)
          _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$_G_sed_quote_subst"` ;;
        *)
          _G_unquoted_arg=$1 ;;
      esac

      case $_G_unquoted_arg in
        # Double-quote args containing shell metacharacters to delay
        # word splitting, command substitution and variable expansion
        # for a subsequent eval.
        # Many Bourne shells cannot handle close brackets correctly
        # in scan sets, so we specify it separately.
        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
          _G_quoted_arg=\"$_G_unquoted_arg\"
          ;;
        *)
          _G_quoted_arg=$_G_unquoted_arg ;;
      esac
      test -n "$func_quote_for_eval_result" \
          && func_append func_quote_for_eval_result " "
      func_append func_quote_for_eval_result "$_G_quoted_arg"
      shift
    done
}


# func_split_equals STRING
# ------------------------
# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
# splitting STRING at the `=' sign.
if (eval 'x='--ab=cd'; y=${x#*=}; z=${x%%=*}; test x$y$z = xcd--ab') 2>/dev/null
then
  # This is an XSI compatible shell, allowing a faster implementation...
  eval 'func_split_equals ()
  {
      $debug_cmd

      func_split_equals_lhs=${1%%=*}
      func_split_equals_rhs=${1#*=}
      test "x$func_split_equals_lhs" = "x$1" \
        && func_split_equals_rhs=
  }'
else
  # ...otherwise fall back to using expr, which is often a shell builtin.
  func_split_equals ()
  {
      $debug_cmd

      func_split_equals_lhs=`expr "x$1" : 'x\([^=]*)'`
      func_split_equals_rhs=
      test "x$func_split_equals_lhs" = "x$1" \
        || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
  }
fi #func_split_equals


# func_split_short_opt SHORTOPT
# -----------------------------
# Set func_split_short_opt_name and func_split_short_opt_arg shell
# variables after splitting SHORTOPT after the 2nd character.
if (eval 'x=-abc; y=${x#??}; z=${x%$y}; test x$y$z = xbc-a') 2>/dev/null
then
  # This is an XSI compatible shell, allowing a faster implementation...
  eval 'func_split_short_opt ()
  {
      $debug_cmd

      func_split_short_opt_arg=${1#??}
      func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
  }'
else
  # ...otherwise fall back to using expr, which is often a shell builtin.
  func_split_short_opt ()
  {
      $debug_cmd

      func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
      func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
  }
fi #func_split_short_opt


# func_usage
# ----------
# Echo short help message to standard output and exit.
func_usage ()
{
    $debug_cmd

    func_usage_message
    $bs_echo "Run \`$progname --help |${PAGER-more}' for full usage"
    exit 0
}


# func_usage_message
# ------------------
# Echo short help message to standard output.
func_usage_message ()
{
    $debug_cmd

    eval \$bs_echo \""$usage"\"
    echo
    $SED -n 's|^# ||;/^Written by/{x;p;x;};h' < "$progpath"
    echo
    eval \$bs_echo \""$usage_message"\"
}


# func_verbose ARG...
# -------------------
# Echo program name prefixed message in verbose mode only.
func_verbose ()
{
    $opt_verbose && func_echo ${1+"$@"}
}


# func_version
# ------------
# Echo version message to standard output and exit.
func_version ()
{
    $debug_cmd

    printf '%s\n' "$progname $scriptversion"
    $SED -n '/(C)/!b go
        :more
        /\./!{
          N
          s|\n# | |
          b more
        }
        :go
        /^# Written by /,/# warranty; / {
          s|^# ||
          s|^# *$||
          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
          p
        }
        /^# Written by / {
          s|^# ||
          p
        }' < "$progpath"

    exit $?
}


# Local variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
